#include "QRenderStructure.h"

QRenderColor::QRenderColor()
{
    this->r = 0;
    this->g = 0;
    this->b = 0;
    this->a = 0;
}

QRenderColor::QRenderColor(unsigned char i)
{
    this->r = i;
    this->g = i;
    this->b = i;
    this->a = 255;
}

QRenderColor::QRenderColor(unsigned char r, unsigned char g, unsigned char b)
{
    this->r = r;
    this->g = g;
    this->b = b;
    this->a = 255;
}

QRenderColor::QRenderColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
    this->r = r;
    this->g = g;
    this->b = b;
    this->a = a;
}

QRenderColor::~QRenderColor()
{

}

QRenderVector3::QRenderVector3()
{
    this->x = 0.0f;
    this->y = 0.0f;
    this->z = 0.0f;
}

QRenderVector3::QRenderVector3(const QRenderVector3 &v)
{
    this->x = v.x;
    this->y = v.y;
    this->z = v.z;
}

QRenderVector3::QRenderVector3(float x, float y, float z)
{
    this->x = x;
    this->y = y;
    this->z = z;
}

QRenderVector3::~QRenderVector3()
{
    
}

QRenderVector3 operator +(const QRenderVector3 &v, const float &f)
{
    return QRenderVector3(v.x + f, v.y + f, v.z + f);
}

QRenderVector3 operator -(const QRenderVector3 &v, const float &f)
{
    return QRenderVector3(v.x - f, v.y - f, v.z - f);
}

QRenderVector3 operator *(const QRenderVector3 & v, const float & f)
{
    return QRenderVector3(v.x * f, v.y * f, v.z * f);
}

QRenderVector3 operator +(const QRenderVector3 &v1, const QRenderVector3 &v2)
{
    return QRenderVector3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
}

QRenderVector3 operator -(const QRenderVector3 &v1, const QRenderVector3 &v2)
{
    return QRenderVector3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
}

QRenderVector3 operator *(const QRenderVector3 &v1, const QRenderVector3 &v2)
{
    return QRenderVector3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z);
}

float QRenderVector3::dot(const QRenderVector3 &v1, const QRenderVector3 &v2)
{
    return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}

QRenderVector3 QRenderVector3::cross(const QRenderVector3 &v1, const QRenderVector3 &v2)
{
    return QRenderVector3(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x);
}

float QRenderVector3::length(const QRenderVector3 &v)
{
    return ::sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
}

QRenderVector3 QRenderVector3::normalize(const QRenderVector3 &v)
{
    float size = QRenderVector3::length(v);
    if (size < EPSILON)
    {
        return QRenderVector3(0.0f, 0.0f, 0.0f);
    }
    else
    {
        float inverse = 1.0f / size;
        return QRenderVector3(v.x * inverse, v.y * inverse, v.z * inverse);
    }
}

QRenderVertex::QRenderVertex()
{
    this->position = QRenderVector3();
    this->color = QRenderColor();
    this->normal = QRenderVector3();
    memset(this->padding, 0, sizeof(this->padding));
}

QRenderVertex::QRenderVertex(const QRenderVector3 &position, const QRenderColor &color, const QRenderVector3 &normal)
{
    this->position = position;
    this->color = color;
    this->normal = normal;
    memset(this->padding, 0, sizeof(this->padding));
}

QRenderVertex::~QRenderVertex()
{

}

QRenderVector4::QRenderVector4()
{
    this->x = 0.0f;
    this->y = 0.0f;
    this->z = 0.0f;
    this->w = 0.0f;
}

QRenderVector4::QRenderVector4(float x, float y, float z, float w)
{
    this->x = x;
    this->y = y;
    this->z = z;
    this->w = w;
}

QRenderVector4::~QRenderVector4()
{
    
}

QRenderVector4 operator *(const QRenderVector4 &t1, const QRenderVector4 &t2)
{
    return QRenderVector4
        (
            t1.w * t2.x + t2.w * t1.x + t1.y * t2.z - t1.z * t2.y,
            t1.w * t2.y + t2.w * t1.y + t1.z * t2.x - t1.x * t2.z,
            t1.w * t2.z + t2.w * t1.z + t1.x * t2.y - t1.y * t2.x,
            t1.w * t2.w - (t1.x * t2.x + t1.y * t2.y + t1.z * t2.z)
        );
}

QRenderVector3 operator *(const QRenderVector4 &t, const QRenderVector3 &v)
{
    QRenderVector3 u(t.x, t.y, t.z);
    float uu = QRenderVector3::dot(u, u);
    float uv = QRenderVector3::dot(u, v);
    return (u * uv + QRenderVector3::cross(u, v) * t.w) *2.0f + v * (t.w * t.w - uu);
}

void QRenderVector4::getAngleAxis(const QRenderVector4 &q, QRenderVector3 &v, float *angle)
{
    float size = (float)::sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
    if (size < EPSILON)
    {
        *angle = 0.0f;
        v = QRenderVector3(0.0f, 0.0f, 1.0f);
    }
    else
    {
        *angle = 2.0f * (float)acos(q.w);
        float inverse = 1.0f / size;
        v = QRenderVector3(q.x * inverse, q.y * inverse, q.z * inverse);
    }
}

QRenderVector4 QRenderVector4::fromAngleAxis(float angle, const QRenderVector3 &axis)
{
    QRenderVector3 v = QRenderVector3::normalize(axis);
    float size = QRenderVector3::length(v); 
    if(size < EPSILON)
    {
        return QRenderVector4(0.0f, 0.0f, 0.0f, 1.0f);
    }
    else
    {
        float inverse = (float)::sin(0.5f * angle) / size;
        return QRenderVector4(v.x * inverse, v.y * inverse, v.z * inverse, (float)::cos(0.5f * angle));
    }
}

QRenderVector4 QRenderVector4::normalize(const QRenderVector4 &q)
{
    float size = (float)::sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
    if (size < EPSILON)
    {
        return QRenderVector4(0.0f, 0.0f, 0.0f, 1.0f);
    }
    else
    {
        float inverse = 1.0f / size;
        return QRenderVector4(q.x * inverse, q.y * inverse, q.z * inverse, q.w * inverse);
    }
}

QRenderVector4 QRenderVector4::inverse(const QRenderVector4 &q)
{
    float size = (float)::sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
    if (size < EPSILON)
    {
        return QRenderVector4(0.0f, 0.0f, 0.0f, 1.0f);
    }
    else
    {
        float inverse = 1.0f / size;
        return QRenderVector4(-q.x * inverse, -q.y * inverse, -q.z * inverse, q.w * inverse);
    }
}